package com.yide.myworld.knowledge;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;

/**
 * Spring事务失效场景总结
 */

@Service
@Slf4j
public class SpringTransactionDemoService {

    /**
     * 加入事务、不调用其他方法（事务生效）
     */
    @Transactional
    public void addMpUserToDB1() {
    }

    /**
     * 不加入事务、最后抛出【运行时异常】（出现异常不会回滚）
     */
    public void addMpUserToDB2() {
    }

    /**
     * 加入事务、最后抛出【运行时异常】（事务生效：出现异常会回滚）
     */
    @Transactional
    public void addMpUserToDB3() {
        addMpUserToDB3_1();
    }

    public void addMpUserToDB3_1() {
    }

    /**
     * 【事务失效场景1 ： 异常被try catch吞掉】
     * 加入事务、最后抛出【运行时异常】、自行try catch（事务失效1：异常会被try catch吞掉，不会进行回滚）
     */
    @Transactional
    public void addMpUserToDB4() {
    }

    /**
     * 【事务失效场景2：抛出的是检查型异常】
     * 加入事务、最后抛出【检查型异常】（事务失效2：出现异常不会回滚）注意：手动指定rollback = ParseException.class后会进行回滚
     */
    @Transactional //(rollbackFor = {ParseException.class})
    public void addMpUserToDB5() throws ParseException {
    }

    /**
     * 加入事务、最后抛出【检查型异常】, 手动指定rollback = ParseException.class后会进行回滚
     */
    @Transactional(rollbackFor = {ParseException.class})
    public void addMpUserToDB6() throws ParseException {
    }

    /**
     * 加入事务、最后抛出【检查型异常】、自行try catch（事务失效：出现异常不会回滚）
     */
    @Transactional(rollbackFor = {ParseException.class})
    public void addMpUserToDB7() {
    }

    /**
     * 【事务失效场景3：本类无事务方法调用本类有事务方法】
     * 当前方法无事务，使用this调用当前类的事务方法（事务失效3：事务方法中出现异常不会回滚）
     * 原理：发生自调用，类里面使用this调用本类的方法，此时这个this不是代理对象，所以事务失效
     */
    public void addMpUserToDB8() {
        addMpUserToDB3();
    }

    /**
     * 当前方法无事务，使用spring容器中对象引用调用当前类的事务方法（事务生效：事务方法中出现异常会回滚）
     * 原理：发生自调用，类里面使用容器中的代理类调用的事务方法，所以事务生效
     */
    public void addMpUserToDB9() {
    }

    public void addMpUserToDB9_1() {
        ((SpringTransactionDemoService) AopContext.currentProxy()).addMpUserToDB3();
    }

    /**
     * 当前方法无事务，调用其他类的事务方法（事务生效：事务方法中出现异常会回滚）
     * 原理：发生自调用，类里面使用容器中其他类的代理对象调用的事务方法，所以事务生效
     */
    public void addMpUserToDB10() {
    }

    /**
     * 当前类有事务方法调用当前类的事务方法（事务生效，下游的事务方法中出现异常会进行全面回滚）
     */
    @Transactional
    public void addMpUserToDB11() {
    }

    /**
     * 【事务失效场景4：事务方法被非public修饰】
     */
    @Transactional
    void addMpUserToDB12() {
    }

    /**
     * 【事务失效场景5：事务方法被final修饰】
     * 被final修饰的方法，代理类中是获取不到成员属性的
     */
    @Transactional
    public final void addMpUserToDB13() {
    }

    /**
     * 【事务失效场景6：设置了错误的传播行为】
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void addMpUserToDB14() {
    }
}
